use crate::constant::{LogLevel, Star, StarInfo};
use crate::math::dynamics;
use crate::math::dynamics::NewtonSecondLow;
use crate::model::auto_logic::RocketAutoLogic;
use crate::model::rocket::Rocket;

/// 执行计算链 返回距离和速度
pub fn exec(star: &impl Star, rocket: &mut Rocket, logic: impl RocketAutoLogic, now: u128, distance: f64, speed: f64, log: LogLevel) -> (f64, f64) {
    // gravitation
    let f1 = -gravitation(&star.info(), &rocket, distance);
    // air_friction
    let f2 = -air_friction(star, &rocket, distance, speed);
    // rocket power
    let rp = rocket._run(now, logic);
    let asp = NewtonSecondLow::calculate_speed(f1 + rp + f2, rocket.current_mass());
    let speed = speed + asp;
    match log {
        LogLevel::TOTAL => {
            println!(" - gravitation: {}N, air_friction: {}N, rocket_power: {}N", f1, f2, rp);
            println!(" - accelerated_speed: {}m/s, current_speed: {}m/s", asp, speed);
            rocket.show();
        }
        LogLevel::MAIN => {
            println!(" - gravitation: {}N, air_friction: {}N, rocket_power: {}N", f1, f2, rp);
            println!(" - accelerated_speed: {}m/s, current_speed: {}m/s", asp, speed);
        }
        LogLevel::LESS => {
            println!(" - gravitation: {}N, air_friction: {}N, rocket_power: {}N", f1, f2, rp);
            println!(" - accelerated_speed: {}m/s, current_speed: {}m/s", asp, speed);
        }
        LogLevel::NONE => {}
    }
    let ground = star.info().radius;
    if (distance - ground) > -speed { (distance + speed, speed) } else { (ground, 0.0) }
}


/// 大气阻力集中计算
fn air_friction(star: &impl Star, rocket: &Rocket, distance: f64, speed: f64) -> f64 {
    let info = star.info();
    let atmosphere = star.catch_atmosphere(distance - info.radius);
    let density = dynamics::air_density(atmosphere.air_pressure, info.atmospheric_gas, atmosphere.temperature);
    dynamics::air_friction(rocket.info().air_drag_factor, density, rocket.info().frontal_area, speed)
}

/// 引力集中计算
fn gravitation(star: &StarInfo, rocket: &Rocket, distance: f64) -> f64 {
    dynamics::gravitation(star.mass, rocket.current_mass(), distance)
}